Virtual Code
roy g biv / defjam
Virtual Code
roy g biv / defjam
-= defjam =-
since 1992
bringing you the viruses of tomorrow
today!
Former DOS/Win16 virus writer, author of several virus families, including
Ginger (see Coderz #1 zine for terrible buggy example, contact me for better
sources ;), and Virus Bulletin 9/95 for a description of what they called
Rainbow. Co-author of world's first virus using circular partition trick
(Orsam, coded with Prototype in 1993). Designer of world's first XMS swapping
virus (John Galt, coded by RT Fishel in 1995, only 30 bytes stub, the rest is
swapped out). Author of world's first virus using Thread Local Storage for
replication (Shrug, see Virus Bulletin 6/02 for a description, but they call
it Chiton), world's first virus using Visual Basic 5/6 language extensions for
replication (OU812), world's first Native executable virus (Chthon), world's
first virus using process co-operation to prevent termination (Gemini, see
Virus Bulletin 9/02 for a description), world's first virus using polymorphic
SMTP headers (JunkMail, see Virus Bulletin 11/02 for a description), world's
first viruses that can convert any data files to infectable objects (Pretext),
world's first 32/64-bit parasitic EPO .NET virus (Croissant, see Virus
Bulletin 11/04 for a description, but they call it Impanate), world's first
virus using self-executing HTML (JunkHTMaiL, see Virus Bulletin 7/03 for a
description), world's first virus for Win64 on Intel Itanium (Shrug, see Virus
Bulletin 6/04 for a description, but they call it Rugrat), world's first virus
for Win64 on AMD AMD64 (Shrug), world's first cross-infecting virus for Intel
IA32 and AMD AMD64 (Shrug), world's first viruses that infect Office
applications and script files using the same code (Macaroni, see Virus
Bulletin 11/05 for a description, but they call it Macar), world's first
viruses that can infect both VBS and JScript using the same code (ACDC, see
Virus Bulletin 11/05 for a description, but they call it Cada), world's first
virus that can infect CHM files (Charm, see Virus Bulletin 10/06 for a
description, but they call it Chamb), world's first IDA plugin virus (Hidan,
see Virus Bulletin 3/07 for a description), world's first viruses that use the
Microsoft Script Encoder to dynamically encrypt the virus body (Screed),
world's first virus for StarOffice and OpenOffice (Starbucks), world's first
virus IDC virus (ID10TiC), world's first polymorphic virus for Win64 on AMD
AMD64 (Boundary, see Virus Bulletin 12/06 for a description, but they call it
Bounds), world's first virus that can infect Intel-format and PowerPC-format
Mach-O files (MachoMan, see Virus Bulletin 01/07 for a description, but
they call it Macarena), world's first virus that uses Unicode escapes to
dynamically encrypt the virus body, world's first self-executing PIF (Spiffy),
and world's first self-executing LNK (WeakLNK). Author of various retrovirus
articles (eg see Vlad #7 for the strings that make your code invisible to
TBScan). This is my fourteenth virus for Win32. It is the world's first
virus to use virtual code.
What is virtual code?
This is an idea that I had after I read about the Locreate in Uninformed #6
journal. There, the author describes about relocation data being used to
alter the in-memory image. We have seen this before, where a virus uses
relocation data to decrypt itself. The author talks about packer but it is
really cryptor. There are some interesting things in the article, but it was
not very special for me. So, my idea is to remove all code from a section,
and use relocation data to restore it. Since the section is now only in
virtual memory, I call it virtual code. It seems that IDA does not support
multiple relocations being applied to the same location, so it cannot handle
my files. :)
This technique was also almost ready for many months, but I work on too many
projects at the same time and finish none of them. Now I have.
How does it work?
The idea is that the section is virtual, so we know that it is full of 00s.
If we set our ImageBase value to 0, then we will be relocated to 0x10000. It
means that if we use relocation types that work with the top 16 bits, then we
can perform many +1 operations on our 00s to reach any value that we want. I
also use relocation types other than the IMAGE_REL_BASED_HIGHLOW that we all
know, to make fewer operations, and it might challenge some emulators. :) We
can apply relocations in any order on each page, so we can even be polymorphic
by ordering the relocations randomly.
Tricky relocations ;)
Some info about relocation data now:
Windows NT does not relocate EXEs, only DLLs.
Windows 2000/XP load to 0x10000 for invalid base, but requested base must be
64kb aligned, else error occurs.
Windows 9x/Me load to 0x400000 for invalid base, and requested base can be any
value.
Windows NT supports types 0-5.
Windows 2000 supports types 0-B.
Windows XP supports types 0-A.
Windows 9x/Me supports types 0-4 only.
Here is a description of the types:
type name function
0 IMAGE_REL_BASED_ABSOLUTE ignored
1 IMAGE_REL_BASED_HIGH adds top 16 bits of delta to word
2 IMAGE_REL_BASED_LOW adds low 16 bits of delta to word
but since Windows requires 64kb aligned images, so these bits are always 0
3 IMAGE_REL_BASED_HIGHLOW adds all 32 bits of delta to dword
4 IMAGE_REL_BASED_HIGHADJ occupies 2 slots
- forms 28-bit big-endian address
- adds delta, aligns to 64kb
- stores top 16 bits
result is always same as type 1 because 64kb alignment
5 IMAGE_REL_BASED_MIPS_JMPADDR weird 32-bit encoding
formula follows:
d[mem]=(((((d[mem]&3FFFFFF)<<2)+delta)>>2)&3FFFFFF)+(d[mem]&FC000000)
useful for quickly reaching mutiple of 40 at offset mem+1
maintains all 8 bits at mem
maintains low 6 bits at mem+1
maintains high 6 bits at mem+3
6 same as type 0
7 same as type 0
8 invalid error occurs if used
9 IMAGE_REL_BASED_MIPS_JMPADDR16 weird 64-bit encoding
formula follows:
mem=oword align ptr
base=((d[mem+4]<<8)&FFC00000)+((d[mem+0c]<<9)&200000)+((d[mem+0c]<<3)&1F0000)+((d[mem+0c]>>b)&FF80)+((d[mem+0c]>>4)&7F)+delta
d[mem+4]=(d[mem+4]&3FFF)|((base>>8)&FFC000)
d[mem+8]&=FF800000
d[mem+c]=((base<>3)&3E000)+((base>>9)&1000)+((base<<4)&7F0)+(d[mem+c]&F000080F)
useful for quickly reaching mutiple of 20 at offset mem+d
maintains all 8 bits at mem
maintains all 8 bits at mem+1
maintains all 8 bits at mem+2
maintains all 8 bits at mem+3
maintains all 8 bits at mem+4
maintains low 6 bits at mem+5
maintains high 1 bit at mem+a
maintains all 8 bits at mem+b
maintains low 4 bits at mem+c
maintains bit 4 at mem+d
maintains high 4 bits at mem+f
A IMAGE_REL_BASED_DIR64 same as type 3 on Window 2000
fully 64-bit on Windows XP
B IMAGE_REL_BASED_HIGHADJ64(?) undocumented
occupies 3 slots
- forms 44-bit big-endian address
- adds delta
- aligns to 64kb
- stores top 16 bits
Other info
Windows processes import table before relocations (because imports are RVAs
not VAs), so relocation data cannot be used to construct import table at
runtime, only to alter it afterwards for obfuscation purposes.
Virtual code section must be writable else file will not load.
Relocation data can be used to alter file header if header is write-enabled by
using < 4kb section alignment, but some fields must not be altered (eg "MZ",
"PE", Machine, NumberOfSections, SizeOfOptionalHeader, Magic).
Changing AddressOfEntrypoint has no effect (value is cached before relocation
data are processed), however relocation data can be used to set ImageBase to
impossible values (non-64kb aligned) and AddressOfEntryPoint can be adjusted
indirectly using that. For example, if you add three bytes to ImageBase, then
it is like subtracting three bytes from AddressOfEntryPoint.
IMAGE_FILE_RELOCS_STRIPPED value in Characteristics field is ignored if image
must be relocated.
Greets to friendly people (A-Z):
Active - Benny - Malum - Obleak - Prototype - Ratter - Ronin - RT Fishel -
sars - SPTH - The Gingerbread Man - Ultras - uNdErX - Vallez - Vecna -
VirusBuster - Whitehead
rgb/defjam oct 2007
iam_rgb@hotmail.com